#include <GL/glut.h>
#include <stdlib.h>

#define MUNDO 4.0f

int figura, opcion, luz1, luz2;
float rX, rY, rZ;
float linearF, quadricF;
float position1[4], position2[4];
unsigned char color[3];

void inicializar (void);
void redimensiona (int alto, int ancho);
void dibuja (void);
void teclado (unsigned char key, int cx, int cy);
void tecladoEspecial (int key, int cy, int cx);
void setColor();
void drawLights();

int main(int argc, char** argv) {
   
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize (640, 480);
   glutInitWindowPosition (100, 105);
   glutCreateWindow (argv[0]);
   inicializar();
   
   glutDisplayFunc(dibuja);
   glutReshapeFunc(redimensiona);
   glutKeyboardFunc(teclado);
   glutSpecialFunc(tecladoEspecial);
  
   glutMainLoop();
   
   return 0;
}

void inicializar () {
   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_LIGHTING);
   
   //glEnable(GL_LIGHT0);
   glEnable(GL_LIGHT1);
   
   position1[0] = 3.0;
   position1[1] = 3.0;
   position1[2] = 0.0;
   position1[3] = 1.0;
   
   
   position2[0] = -3.0;
   position2[1] = -3.0;
   position2[2] = 0.0;
   position2[3] = 1.0;
   
   float def[] = {1.0, 1.0, 1.0, 1.0};
   glLightfv(GL_LIGHT1, GL_DIFFUSE, def);
   glLightfv(GL_LIGHT1, GL_SPECULAR, def);
   
   glEnable(GL_COLOR_MATERIAL);
   glColorMaterial(GL_FRONT, GL_DIFFUSE);
   figura = 1;
   linearF = 0.0;
   quadricF = 0.0;
   opcion = 1;
   luz1 = 1;
   luz2 = 1;
}

void redimensiona (int ancho, int alto) {
   float aspect;
   
   glViewport (0, 0, ancho, alto);
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
   
   if (alto == 0){
   	  alto = 1;
   }
   
   aspect = (float) ancho / (float) alto;
   
   if (ancho <= alto) {
   	  glOrtho(-MUNDO, MUNDO, -MUNDO/aspect, MUNDO/aspect, -MUNDO, MUNDO);
   } else {
   	  glOrtho(-MUNDO * aspect, MUNDO * aspect, -MUNDO, MUNDO, -MUNDO, MUNDO);
   }
   
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}

void teclado (unsigned char key, int cx, int cy) {
	
	switch (key) {
		case 27:
		   exit(0);
		break;
		
		case 'a':
			if (linearF > 0.0)
			   linearF -= 0.1;
			else
			   linearF = 0.0;
			glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, linearF);
		break;
		
		case 'A':
			   linearF += 0.1;
			glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, linearF);
		break;
		
		case 's':
		    if (quadricF > 0.0)
			   quadricF -= 0.1;
			else
			   quadricF = 0.0;
			glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, quadricF);
		break;
		
		case 'S':
			quadricF += 0.1;
			glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, quadricF);
		break;
		
		case ' ':
		    opcion++;
		    opcion %= 5;
		break;
		
		case 'x':
		    luz1 = !(luz1);
		    luz1 ? glEnable(GL_LIGHT0) : glDisable(GL_LIGHT0);
		break;
		
		case 'z':
		    luz2 = !(luz2);
		    luz2 ? glEnable(GL_LIGHT1) : glDisable(GL_LIGHT1);
		break;
		
		default: break;
	}
	
	glutPostRedisplay();
}

void tecladoEspecial (int key, int cy, int cx) {
	
	switch (key) {
		case GLUT_KEY_F1:
			figura = 1;
		break;
		
		case GLUT_KEY_F2:
			figura = 2;
		break;
		
		case GLUT_KEY_F3:
			figura = 3;
		break;
		
		case GLUT_KEY_F4:
			figura = 4;
		break;
		
		case GLUT_KEY_F5:
			figura = 5;
		break;
		
		case GLUT_KEY_UP:
			rX -= 10.0;
		break;
		
		case GLUT_KEY_DOWN:
			rX += 10.0;
		break;
		
		case GLUT_KEY_LEFT:
			rY += 10.0;
		break;
		
		case GLUT_KEY_RIGHT:
			rY -= 10.0;
		break;
		
		case GLUT_KEY_PAGE_UP:
			rZ -= 10.0;
		break;
		
		case GLUT_KEY_PAGE_DOWN:
			rZ += 10.0;
		break;
		
		default: break;
	}
	
	glutPostRedisplay();
}

void dibuja (void) {
	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	
	
	glPushMatrix();
	glRotatef(rX, 1.0, 0.0, 0.0);
	glRotatef(rY, 0.0, 1.0, 0.0);
	glRotatef(rZ, 0.0, 0.0, 1.0);
	
	drawLights();
	
	setColor();
	glColor3ubv(color);
	
	switch(figura) {
		case 1:
			glutSolidSphere(1.0, 30, 30);
		break;
		
		case 2:
			glutSolidTorus(0.5, 1.0, 80, 30);
		break;
		
		case 3:
			glutSolidCube(2.0);
		break;
		
		case 4:
			glutSolidTeapot(1.0);
		break;
		
		case 5:
			glPushMatrix();
			   glTranslatef(0.0, 1.0, 0.0);
			   glRotatef(-90.0, 1.0, 0.0, 0.0);
			   glutSolidCone(1.0, 2.0, 20, 30);
			glPopMatrix();
			glPushMatrix();
			   glScalef(1.0, 2.0, 1.0);
			   glutSolidCube(1.0);
			glPopMatrix();
		break;
		
		default:
		break;
	}
	glPopMatrix();
	    
	glFlush();
}

void setColor() {
	
	switch(opcion) {
		case 0:
			color[0] = 48;
			color[1] = 16;
			color[2] = 0;
		break;
		
		case 1:
			color[0] = 255;
			color[1] = 165;
			color[2] = 0;
		break;
		
		case 2:
			color[0] = 173;
			color[1] = 216;
			color[2] = 230;
		break;
		
		case 3:
			color[0] = 139;
			color[1] = 105;
			color[2] = 20;
		break;
		
		case 4:
			color[0] = 165;
			color[1] = 42;
			color[2] = 42;
		break;
		
		case 5:
			color[0] = 47;
			color[1] = 104;
			color[2] = 5;
		break;
		
		default:
		break;
	}	
}

void drawLights() {
	glColor3f(1.0, 1.0, 1.0);
	//luz1
	glPushMatrix();
		glLightfv(GL_LIGHT0, GL_POSITION, position1);
		glTranslatef(position1[0], position1[1], position1[2]);
		glutSolidSphere(0.25, 10, 10);
	glPopMatrix();
	//luz2
	glPushMatrix();
		glLightfv(GL_LIGHT1, GL_POSITION, position2);
		glTranslatef(position2[0], position2[1], position2[2]);
		glutSolidSphere(0.25, 10, 10);
	glPopMatrix();
}
